package xyz.heyaoshare.core.service.system.impl;

import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.CacheableServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xyz.heyaoshare.common.constants.CacheKey;
import xyz.heyaoshare.common.entity.bo.ResultPage;
import xyz.heyaoshare.core.controller.system.role.vo.req.*;
import xyz.heyaoshare.core.controller.system.role.vo.resp.RoleDetailRespVO;
import xyz.heyaoshare.core.controller.system.role.vo.resp.RoleListRespVO;
import xyz.heyaoshare.core.controller.system.role.vo.resp.RolePageRespVO;
import xyz.heyaoshare.core.controller.system.role.vo.resp.RolePermissionRespVO;
import xyz.heyaoshare.core.entity.system.Role;
import xyz.heyaoshare.core.entity.system.RoleMenu;
import xyz.heyaoshare.core.entity.system.UserRole;
import xyz.heyaoshare.core.enums.system.role.RoleStatusEnum;
import xyz.heyaoshare.core.mapper.system.RoleMapper;
import xyz.heyaoshare.core.mapper.system.RoleMenuMapper;
import xyz.heyaoshare.core.service.system.RoleService;
import xyz.heyaoshare.utils.BeanUtils;
import xyz.heyaoshare.utils.CollUtils;
import xyz.heyaoshare.utils.StrUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

import static xyz.heyaoshare.exceptions.code.ErrorInfo.*;
import static xyz.heyaoshare.exceptions.customize.ServerException.exception;

/**
 * 角色 Service 实现类
 * @author YueHe
 * @version 0.0.1
 * @since 2025/6/25 下午2:04
 */
@Slf4j
@Service
@CacheConfig(cacheNames = CacheKey.ROLE_SERVICE)
public class RoleServiceImpl extends CacheableServiceImpl<RoleMapper, Role> implements RoleService {

    @Resource
    private RoleMapper roleMapper;
    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(RoleInsertReqVO reqVO) {
        // 1.校验角色编码是否重复
        long count = QueryChain.of(Role.class).eq(Role::getCode, reqVO.getCode()).count();
        if (count > 0) throw exception(ROLE_CODE_REPEAT);

        try {
            // 2.插入数据
            Role role = new Role()
                    .setName(reqVO.getName())
                    .setCode(reqVO.getCode())
                    .setStatus(RoleStatusEnum.ENABLE.getValue())
                    .setRemark(reqVO.getRemark());
            roleMapper.insert(role);

            return role.getId();
        } catch (Exception e) {
            log.error("新增角色失败", e);
            throw exception(INSERT_ROLE_FAILED);
        }
    }

    @Override
    public ResultPage<RolePageRespVO> selectPage(RolePageReqVO reqVO) {
        // 1.查询数据
        Page<Role> page = QueryChain.of(Role.class)
                .like(Role::getName, reqVO.getName(), StrUtils.isNotBlank(reqVO.getName()))
                .orderBy(Role::getCreateTime, Boolean.FALSE)
                .page(new Page<>(reqVO.getPage(), reqVO.getSize()));

        // 2.转换数据
        List<RolePageRespVO> items = Optional.ofNullable(page.getRecords()).orElseGet(ArrayList::new).stream().map(item -> {
            RolePageRespVO respVO = BeanUtils.copyProperties(item, RolePageRespVO.class);
            respVO.setStatusStr(RoleStatusEnum.getLabel(item.getStatus()));
            return respVO;
        }).toList();

        // 3.返回数据
        return ResultPage.result(page.getTotalRow(), items);
    }

    @Override
    public List<RoleListRespVO> selectList(RoleListReqVO reqVO) {
        // 1.查询数据
        List<Role> list = QueryChain.of(roleMapper)
                .eq(Role::getStatus, RoleStatusEnum.ENABLE.getValue())
                .orderBy(Role::getCreateTime, Boolean.FALSE)
                .list();

        // 2.转换数据并返回
        return Optional.ofNullable(list).orElseGet(ArrayList::new).stream().map(item -> {
            RoleListRespVO respVO = BeanUtils.copyProperties(item, RoleListRespVO.class);
            respVO.setStatusStr(RoleStatusEnum.getLabel(item.getStatus()));
            return respVO;
        }).toList();
    }

    @Override
    public RoleDetailRespVO selectDetail(RoleDetailReqVO reqVO) {
        Role role = roleMapper.selectOneById(reqVO.getRoleId());
        if (role == null) throw exception(ROLE_NOT_EXIST);

        RoleDetailRespVO roleDetailRespVO = BeanUtils.copyProperties(role, RoleDetailRespVO.class);
        roleDetailRespVO.setStatusStr(RoleStatusEnum.getLabel(role.getStatus()));
        return roleDetailRespVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(RoleDeleteReqVO reqVO) {
        // 1.校验角色是否被使用
        List<Long> roleIds = reqVO.getRoleIds();
        for (Long roleId : roleIds) {
            // 如果角色已经被使用,不允许被删除
            long count = QueryChain.of(UserRole.class).eq(UserRole::getRoleId, roleId).count();
            if (count > 0) {
                Role role = getById(roleId);
                if (role != null) throw exception(ROLE_IN_USE, role.getName());
            }
        }

        try {
            // 2.删除角色 和 菜单关联信息
            UpdateChain.of(Role.class).in(Role::getId, roleIds).remove();
            UpdateChain.of(RoleMenu.class).in(RoleMenu::getRoleId, roleIds).remove();
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("删除角色失败", e);
            throw exception(DELETE_ROLE_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateData(RoleUpdateReqVO reqVO) {
        // 1.校验类型名是否重复
        long count = QueryChain.of(Role.class).ne(Role::getId, reqVO.getId()).eq(Role::getCode, reqVO.getCode()).count();
        if (count > 0) throw exception(ROLE_CODE_REPEAT);

        try {
            // 2.更新数据
            UpdateChain.of(Role.class)
                    .set(Role::getName, reqVO.getName())
                    .set(Role::getCode, reqVO.getCode())
                    .set(Role::getRemark, reqVO.getRemark())
                    .eq(Role::getId, reqVO.getId())
                    .update();
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("更新角色失败", e);
            throw exception(UPDATE_ROLE_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateStatus(RoleUpdateStatusReqVO reqVO) {
        try {
            // 1.获取原始状态
            Role role = QueryChain.of(Role.class).eq(Role::getId, reqVO.getId()).one();
            if (role == null) throw exception(ROLE_NOT_EXIST);

            // 2.更新数据
            UpdateChain.of(Role.class)
                    .set(Role::getStatus, role.getStatus() == RoleStatusEnum.ENABLE.getValue() ? RoleStatusEnum.DISABLE.getValue() : RoleStatusEnum.ENABLE.getValue())
                    .eq(Role::getId, reqVO.getId())
                    .update();

            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("更新角色状态失败", e);
            throw exception(UPDATE_ROLE_STATUS_FAILED);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean setPermissions(RoleSetPermissionReqVO reqVO) {
        // 1.获取原始的菜单权限列表
        List<RoleMenu> list = QueryChain.of(RoleMenu.class).eq(RoleMenu::getRoleId, reqVO.getRoleId()).select(RoleMenu::getMenuId).list();
        List<Long> menuIds = Optional.ofNullable(list).orElseGet(ArrayList::new).stream().map(RoleMenu::getMenuId).filter(Objects::nonNull).toList();

        // 2.获取需要新增和删除的Id列表
        List<Long> insertIds = CollUtils.subtractToList(reqVO.getPermissionIds(), menuIds);
        List<Long> deleteIds = CollUtils.subtractToList(menuIds, reqVO.getPermissionIds());

        // 3.执行新增处理
        if (CollUtils.isNotEmpty(insertIds)) {
            List<RoleMenu> insertList = new ArrayList<>();
            for (Long menuId : insertIds) {
                RoleMenu roleMenu = new RoleMenu().setRoleId(reqVO.getRoleId()).setMenuId(menuId);
                insertList.add(roleMenu);
            }
            if (CollUtils.isNotEmpty(insertList)) {
                try {
                    roleMenuMapper.insertBatch(insertList);
                } catch (Exception e) {
                    log.error("新增角色菜单失败", e);
                    throw exception(INSERT_ROLE_MENU_FAILED);
                }
            }
        }

        // 4.执行新增处理
        if (CollUtils.isNotEmpty(deleteIds)) {
            try {
                UpdateChain.of(RoleMenu.class).eq(RoleMenu::getRoleId, reqVO.getRoleId()).in(RoleMenu::getMenuId, deleteIds).remove();
            } catch (Exception e) {
                log.error("删除角色菜单失败", e);
                throw exception(DELETE_ROLE_MENU_FAILED);
            }
        }

        return Boolean.TRUE;
    }

    @Override
    public RolePermissionRespVO getPermissions(RolePermissionReqVO reqVO) {
        List<RoleMenu> list = QueryChain.of(roleMenuMapper).eq(RoleMenu::getRoleId, reqVO.getRoleId()).select(RoleMenu::getMenuId).list();
        List<Long> menuIds = Optional.ofNullable(list).orElseGet(ArrayList::new).stream().map(RoleMenu::getMenuId).filter(Objects::nonNull).toList();

        return new RolePermissionRespVO().setRoleId(reqVO.getRoleId()).setPermissionIds(menuIds);
    }

}